home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / freeWAIS-sf-1.1 / ir / soundex.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-06  |  20.2 KB  |  614 lines

  1. /****************************************************************************
  2. *****************************************************************************
  3. FILE      : soundex.c
  4. FUNCTION  : This module contains the two algorithms SOUNDEX and PHONIX as 
  5.             they were defined by Gadd.
  6. NOTES     : This is an ANSI-C version of the original C++ file.
  7. LITERATURE: T.N. Gadd: 'Fishing fore Werds': Phonetic Retrieval of written 
  8.             text in Information Retrieval Systems, Program 22/3, 1988, 
  9.             p.222-237.
  10.             T.N. Gadd: PHONIX --- The Algorithm, Program 24/4, 1990, 
  11.             p.363-366.
  12. *****************************************************************************
  13. ****************************************************************************/
  14.  
  15. /* #define TEST */       /* activates procedures main() and PrintCode() */
  16. /* #define DEBUG */      /* activates some debug information            */
  17.  
  18. #include "cdialect.h"
  19.  
  20. /****************************************************************************
  21. NAME    : StrDel
  22. INPUT   : char *DelPos --- pointer to first char to be deleted
  23.           int  DelSize --- number of chars to be deleted
  24. OUTPUT  : char *DelPos 
  25. FUNCTION: This procedure deletes DelSize chars at position DelPos and moves
  26.           the remaining chars left to DelPos.
  27. EXAMPLE : If Del is pointing at the L of the string "DELETE" the call
  28.           StrDel(Del, 2) will return Del pointing at "TE". 
  29. ****************************************************************************/
  30. void StrDel (DelPos, DelSize)
  31. char *DelPos;
  32. int  DelSize;
  33. {
  34.   /* move chars left */
  35.   char *Help = DelPos + DelSize;
  36.   while (*Help)
  37.     *DelPos++ = *Help++;
  38.  
  39.   /* move trailing \0 */
  40.   *DelPos = *Help;
  41. }
  42.  
  43.  
  44. /****************************************************************************
  45. NAME    : StrIns
  46. INPUT   : char *InsPos --- pointer to insert position
  47. OUTPUT  : char *InStr  --- new string to be inserted
  48. FUNCTION: StrIns moves the chars at position InsPos right and copies the
  49.           string InsStr into this free space.
  50. EXAMPLE : If Ins is pointing at the S of the string "INSERT" the call
  51.           StrIns(Ins, "NEW") will return Ins pointing at "NEWSERT". 
  52. ****************************************************************************/
  53. void StrIns (InsPos, InsStr)
  54. char *InsPos;
  55. char *InsStr;
  56. {
  57.   int i;
  58.   int MoveSize = strlen(InsStr);
  59.  
  60.   /* move chars right */
  61.   for (i = strlen(InsPos)+1; i >= 0; i--)
  62.     InsPos[i+MoveSize] = InsPos[i];
  63.  
  64.   /* copy InsStr to InsPos */
  65.   while (*InsStr)
  66.     *InsPos++ = *InsStr++;
  67. }
  68.  
  69.  
  70. /****************************************************************************
  71. NAME    : IsVowel
  72. INPUT   : char c --- char to be examined
  73. OUTPUT  : int    --- 1 or 0
  74. FUNCTION: IsVowel checks if c is an uppercase vowel or an uppercase Y. If c
  75.           is one of those chars IsVowel will return a 1, else it will return
  76.           a 0.
  77. ****************************************************************************/
  78. int IsVowel (c)
  79. unsigned char c;
  80. {
  81.   return (c == 'A') || (c == 'E') || (c == 'I') ||
  82.     (c == 'O') || (c == 'U') || (c == 'Y') ||
  83.       (c == 0304) || (c == 0344) || (c == 0334) ||
  84.         (c == 0366) || (c == 0326) || (c == 0374);
  85. }
  86.  
  87.  
  88. /****************************************************************************
  89. NAME    : SoundexCode
  90. INPUT   : char *Name --- string to be calculated
  91. OUTPUT  : char *Key  --- soundex code for Name
  92. FUNCTION: This procedure calculates a four-letter soundex code for the string 
  93.           Name and returns this code in the string Key.
  94. ****************************************************************************/
  95. #define SoundexLen 4      /* length of a soundex code */
  96. #define SoundexKey "Z000" /* default key for soundex code */
  97.  
  98. char SCode(c)
  99. unsigned char c;
  100. {
  101.   /* set letter values */
  102.   static int  Code[] = {0, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0, 
  103.                           1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2};
  104.  
  105.   if (c == 95) return(2); /* german sz */
  106.   return(Code[toupper(c)-'A']);
  107. }
  108.  
  109. void SoundexCode (Name, Key)
  110. char *Name;
  111. char *Key;
  112. {
  113.   char LastLetter;
  114.   int  Index;
  115.  
  116.   /* set default key */
  117.   strcpy(Key, SoundexKey);
  118.  
  119.   /* keep first letter */
  120.   Key[0] = *Name;
  121.   LastLetter = *Name;
  122.   Name++;
  123.  
  124.   /* scan rest of string */
  125.   for (Index = 1; (Index < SoundexLen) && *Name; Name++)
  126.   {
  127.     /* use only letters */
  128.     if (isalpha(*Name))
  129.     {
  130.       /* ignore duplicate successive chars */
  131.       if (LastLetter != *Name)
  132.       {
  133.         /* new LastLetter */
  134.         LastLetter = *Name;
  135.  
  136.         /* ignore letters with code 0 */
  137.         if (SCode(*Name) != 0)
  138.         {
  139.           Key[Index] = '0' + SCode(*Name);
  140.           Index++;
  141.         }
  142.       }
  143.     }
  144.   }
  145. }
  146.  
  147.  
  148. /****************************************************************************
  149. NAME    : PhonixCode
  150. INPUT   : char *Name --- string to be calculated
  151. OUTPUT  : char *Key  --- phonix code for Name
  152. FUNCTION: This procedure calculates a eight-letter phonix code for the string 
  153.           Name and returns this code in the string Key.
  154. ****************************************************************************/
  155. #define PhonixLen 8          /* length of a phonix code */
  156. #define PhonixKey "Z0000000" /* default key for phonix code */
  157.  
  158. void PhonixCode (Name, Key)
  159. char *Name;
  160. char *Key;
  161. {
  162.   int  Code[25];
  163.   char LastLetter;
  164.   int  Index;
  165.  
  166.   /* set letter values */
  167.   Code[0]  = 0;
  168.   Code[1]  = 1;
  169.   Code[2]  = 2;
  170.   Code[3]  = 3;
  171.   Code[4]  = 0;
  172.   Code[5]  = 7;
  173.   Code[6]  = 2;
  174.   Code[7]  = 0;
  175.   Code[8]  = 0;
  176.   Code[9]  = 2;
  177.   Code[10] = 2;
  178.   Code[11] = 4;
  179.   Code[12] = 5;
  180.   Code[13] = 5;
  181.   Code[14] = 0;
  182.   Code[15] = 1;
  183.   Code[16] = 2;
  184.   Code[17] = 6;
  185.   Code[18] = 8;
  186.   Code[19] = 3;
  187.   Code[20] = 0;
  188.   Code[21] = 7;
  189.   Code[22] = 0;
  190.   Code[23] = 8;
  191.   Code[24] = 0;
  192.   Code[25] = 8;
  193.  
  194.   /* set default key */
  195.   strcpy(Key, PhonixKey);
  196.  
  197.   /* keep first letter or replace it with '$' */
  198.   Key[0] = IsVowel(*Name) ? '$' : *Name;
  199.   LastLetter = *Name;
  200.   Name++;
  201.  
  202.   /* NOTE: Gadd replaces vowels being the first letter of the  */
  203.   /* word with a 'v'. Due to the implementation of WAIS all    */
  204.   /* letters will be lowercased. Therefore '$' is used instead */
  205.   /* of 'v'.                                                   */          
  206.  
  207.   /* scan rest of string */
  208.   for (Index = 1; (Index < PhonixLen) && *Name; Name++)
  209.   {
  210.     /* use only letters */
  211.     if (isalpha(*Name))
  212.     {
  213.       /* ignore duplicate successive chars */
  214.       if (LastLetter != *Name)
  215.       {
  216.         LastLetter = *Name;
  217.  
  218.         /* ignore letters with code 0 except as separators */
  219.         if (Code[toupper(*Name)-'A'] != 0)
  220.         {
  221.           Key[Index] = '0' + Code[toupper(*Name)-'A'];
  222.           Index++;
  223.         }
  224.       }
  225.     }
  226.   }
  227. }
  228.  
  229.  
  230. /****************************************************************************
  231. NAME    : PhonixReplace1
  232. INPUT   : int  where    --- replace OldStr only if it occurs at this position
  233.           char *Name    --- string to work
  234.           char *OldStr  --- old letter group to delete
  235.           char *NewStr  --- new letter group to insert
  236.           int  CondPre  --- condition referring to letter before OldStr
  237.           int  CondPost --- condition referring to letter after OldStr
  238. OUTPUT  : char *Name    --- Name with replaced letter group
  239. FUNCTION: This procedure replaces the letter group OldStr with the letter 
  240.           group NewStr in the string Name, regarding the position of OldStr
  241.           where (START, MIDDLE, END, ALL) and the conditions CondPre and 
  242.           CondPost (NON, VOC, CON).
  243. EXAMPLE : PhonixReplace1(START, "WAWA", "W", "V", NON, NON) replaces only the
  244.           first W with a V because of the condition START.
  245. EXAMPLE : PhonixReplace1(START, "WAWA", "W", "V", NON, CON) replaces neither
  246.           the first W with a V (because of the condition CON, i.e. a consonant
  247.           must follow the W) nor the second W (because of the condition START).
  248. ****************************************************************************/
  249. #define NON    1  /* no condition     */
  250. #define VOC    2  /* vowel needed     */ 
  251. #define CON    3  /* consonant needed */
  252.  
  253. #define START  1  /* condition refers to beginning of Name */
  254. #define MIDDLE 2  /* condition refers to middle of Name    */
  255. #define END    3  /* condition refers to EndPos of Name    */
  256. #define ALL    4  /* condition refers to whole Name        */
  257.  
  258. void PhonixReplace1 (Where, Name, OldStr, NewStr, CondPre, CondPost)
  259. int  Where;
  260. char *Name;
  261. char *OldStr;
  262. char *NewStr;
  263. int  CondPre;
  264. int  CondPost;
  265. {
  266.   char *OldStrPos;
  267.   char *EndPos;
  268.   char *NamePtr = Name;
  269.  
  270.   /* vowels before or after OldStr */
  271.   char LetterPre;  /* letter before OldStr */
  272.   char LetterPost; /* letter after OldStr  */
  273.   int  VowelPre;   /* LetterPre is vowel?  */
  274.   int  VowelPost;  /* LetterPost is vowel? */
  275.   int  OkayPre;    /* pre-condition okay?  */
  276.   int  OkayPost;   /* post-condition okay? */
  277.  
  278.   do
  279.   { 
  280.     /* find OldStr in NamePtr */
  281.     OldStrPos = strstr(NamePtr, OldStr);
  282.  
  283.     /* find EndPos of Name */
  284.     EndPos = &Name[strlen(Name)-strlen(OldStr)];
  285.  
  286.     /* check conditions if OldStrPos != NULL */
  287.     if (OldStrPos)
  288.     {
  289.       /* vowel before OldStrPos */
  290.       LetterPre = *(OldStrPos-1);
  291.       /* vowel after OldStrPos+strlen(OldStr) */
  292.       LetterPost = *(OldStrPos+strlen(OldStr));
  293.  
  294.       /* check conditions */
  295.       switch (CondPre)
  296.       {
  297.         case NON: OkayPre = 1;
  298.                   break;
  299.         case VOC: OkayPre = LetterPre ? IsVowel(LetterPre) : 0;
  300.                   break;
  301.         case CON: OkayPre = LetterPre ? !IsVowel(LetterPre) : 0;
  302.                   break;
  303.         default : OkayPre = 0;
  304.                   break;
  305.       }
  306.       switch (CondPost)
  307.       {
  308.         case NON: OkayPost = 1;
  309.                   break;
  310.         case VOC: OkayPost = LetterPost ? IsVowel(LetterPost) : 0;
  311.                   break;
  312.         case CON: OkayPost = LetterPost ? !IsVowel(LetterPost) : 0;
  313.                   break;
  314.         default : OkayPost = 0;
  315.                   break;
  316.       }
  317.     }
  318.  
  319.     /* replace OldStr with NewStr */
  320.     if (OldStrPos && OkayPre && OkayPost &&
  321.        ((Where == START)  && (OldStrPos == Name) ||
  322.         (Where == MIDDLE) && (OldStrPos != Name) && (OldStrPos != EndPos) ||
  323.         (Where == END)    && (OldStrPos == EndPos)  ||
  324.         (Where == ALL)))
  325.     {
  326.       /* replace old letter group with new letter group */
  327.       StrDel(OldStrPos, strlen(OldStr));
  328.       StrIns(OldStrPos, NewStr);
  329.  
  330.       /* advance NamePtr to the position of OldStr */
  331.       NamePtr = OldStrPos;
  332.  
  333. #ifdef DEBUG
  334.       printf("Replace = %s-->%s\n", OldStr, NewStr);  
  335. #endif /* DEBUG */
  336.     }
  337.     else
  338.       /* advance NamePtr one char */
  339.       NamePtr++;
  340.   }
  341.   while (OldStrPos);
  342. }
  343.  
  344.  
  345. /****************************************************************************
  346. NAME    : PhonixReplace2
  347. INPUT   : int  where   --- replace OldStr only if it occurs at this position
  348.           char *Name   --- string to work
  349.           char *OldStr --- old letter group to delete
  350.           char *NewStr --- new letter group to insert
  351. OUTPUT  : char *Name   --- Name with replaced letter group
  352. FUNCTION: This procedure replaces the letter group OldStr with the letter 
  353.           group NewStr in the string Name, regarding the position of OldStr
  354.           where (START, MIDDLE, END, ALL).
  355. EXAMPLE : PhonixReplace2(START, "WAWA", "W", "V") replaces only the first W 
  356.           with a V because of the condition START.
  357. ****************************************************************************/
  358. void PhonixReplace2 (Where, Name, OldStr, NewStr)
  359. int  Where;
  360. char *Name;
  361. char *OldStr;
  362. char *NewStr;
  363. {
  364.   char *OldStrPos;
  365.   char *EndPos;
  366.   char *NamePtr = Name;
  367.  
  368.   do
  369.   { 
  370.     /* find OldStr in NamePtr */
  371.     OldStrPos = strstr(NamePtr, OldStr);
  372.  
  373.     /* find EndPos of Name */
  374.     EndPos = &Name[strlen(Name)-strlen(OldStr)];
  375.  
  376.     /* replace OldStr with NewStr */
  377.     if (OldStrPos &&
  378.        ((Where == START)  && (OldStrPos == Name) ||
  379.         (Where == MIDDLE) && (OldStrPos != Name) && (OldStrPos != EndPos) ||
  380.         (Where == END)    && (OldStrPos == EndPos)  ||
  381.         (Where == ALL)))
  382.     { 
  383.       /* replace old letter group with new letter group */
  384.       StrDel(OldStrPos, strlen(OldStr));
  385.       StrIns(OldStrPos, NewStr);
  386.  
  387.       /* advance NamePtr to the position of OldStr */
  388.       NamePtr = OldStrPos;
  389.  
  390. #ifdef DEBUG
  391.       printf("Replace = %s-->%s\n", OldStr, NewStr);  
  392. #endif /* DEBUG */
  393.     }
  394.     else
  395.       /* advance NamePtr one char */
  396.       NamePtr++;
  397.   }
  398.   while (OldStrPos);
  399. }
  400.  
  401.  
  402. /****************************************************************************
  403. NAME    : Phonix
  404. INPUT   : char *Name --- string to calculate phonix code for
  405. OUTPUT  : char *Key  --- phonix code of Name
  406. FUNCTION: Phonix calculates the phonix code for the string Name.
  407. ****************************************************************************/
  408. void Phonix (Name, Key)
  409. char *Name;
  410. char *Key;
  411. {
  412.   /* use new variable NewName to remain Name unchanged */
  413.   char NewName[50];
  414.   int  i;
  415.  
  416.   strcpy(NewName, Name);
  417.  
  418.   /* uppercase NewName */
  419.   for (i=0; i < strlen(NewName); i++)
  420.     if (islower(NewName[i])) 
  421.       NewName[i] = toupper(NewName[i]);
  422.  
  423. #ifdef DEBUG
  424.   printf("Name    = %s\n", NewName);  
  425. #endif /* DEBUG */
  426.  
  427.   /* replace letter groups according to Gadd's definition */
  428.   PhonixReplace2(ALL   , NewName, "DG"   , "G"    );
  429.   PhonixReplace2(ALL   , NewName, "CO"   , "KO"   );
  430.   PhonixReplace2(ALL   , NewName, "CA"   , "KA"   );
  431.   PhonixReplace2(ALL   , NewName, "CU"   , "KU"   );
  432.   PhonixReplace2(ALL   , NewName, "CY"   , "SI"   );
  433.   PhonixReplace2(ALL   , NewName, "CI"   , "SI"   );
  434.   PhonixReplace2(ALL   , NewName, "CE"   , "SE"   );
  435.   PhonixReplace1(START , NewName, "CL"   , "KL"   , NON, VOC);
  436.   PhonixReplace2(ALL   , NewName, "CK"   , "K"    );
  437.   PhonixReplace2(END   , NewName, "GC"   , "K"    );
  438.   PhonixReplace2(END   , NewName, "JC"   , "K"    );
  439.   PhonixReplace1(START , NewName, "CHR"  , "KR"   , NON, VOC);
  440.   PhonixReplace1(START , NewName, "CR"   , "KR"   , NON, VOC);
  441.   PhonixReplace2(START , NewName, "WR"   , "R"    );
  442.   PhonixReplace2(ALL   , NewName, "NC"   , "NK"   );
  443.   PhonixReplace2(ALL   , NewName, "CT"   , "KT"   );
  444.   PhonixReplace2(ALL   , NewName, "PH"   , "F"    );
  445.   PhonixReplace2(ALL   , NewName, "AA"   , "AR"   );
  446.   PhonixReplace2(ALL   , NewName, "SCH"  , "SH"   );
  447.   PhonixReplace2(ALL   , NewName, "BTL"  , "TL"   );
  448.   PhonixReplace2(ALL   , NewName, "GHT"  , "T"    );
  449.   PhonixReplace2(ALL   , NewName, "AUGH" , "ARF"  );
  450.   PhonixReplace1(MIDDLE, NewName, "LJ"   , "LD"   , VOC, VOC);
  451.   PhonixReplace2(ALL   , NewName, "LOUGH", "LOW"  );
  452.   PhonixReplace2(START , NewName, "Q"    , "KW"   );
  453.   PhonixReplace2(START , NewName, "KN"   , "N"    );
  454.   PhonixReplace2(END   , NewName, "GN"   , "N"    );
  455.   PhonixReplace2(ALL   , NewName, "GHN"  , "N"    );
  456.   PhonixReplace2(END   , NewName, "GNE"  , "N"    );
  457.   PhonixReplace2(ALL   , NewName, "GHNE" , "NE"   );
  458.   PhonixReplace2(END   , NewName, "GNES" , "NS"   );
  459.   PhonixReplace2(START , NewName, "GN"   , "N"    );
  460.   PhonixReplace1(MIDDLE, NewName, "GN"   , "N"    , NON, CON);
  461.   PhonixReplace1(END   , NewName, "GN"   , "N"    , NON, NON); /* NON,CON */
  462.   PhonixReplace2(START , NewName, "PS"   , "S"    );
  463.   PhonixReplace2(START , NewName, "PT"   , "T"    );
  464.   PhonixReplace2(START , NewName, "CZ"   , "C"    );
  465.   PhonixReplace1(MIDDLE, NewName, "WZ"   , "Z"    , VOC, NON);
  466.   PhonixReplace2(MIDDLE, NewName, "CZ"   , "CH"   );
  467.   PhonixReplace2(ALL   , NewName, "LZ"   , "LSH"  );
  468.   PhonixReplace2(ALL   , NewName, "RZ"   , "RSH"  );
  469.   PhonixReplace1(MIDDLE, NewName, "Z"    , "S"    , NON, VOC);
  470.   PhonixReplace2(ALL   , NewName, "ZZ"   , "TS"   );
  471.   PhonixReplace1(MIDDLE, NewName, "Z"    , "TS"   , CON, NON);
  472.   PhonixReplace2(ALL   , NewName, "HROUG", "REW"  );
  473.   PhonixReplace2(ALL   , NewName, "OUGH" , "OF"   );
  474.   PhonixReplace1(MIDDLE, NewName, "Q"    , "KW"   , VOC, VOC);
  475.   PhonixReplace1(MIDDLE, NewName, "J"    , "Y"    , VOC, VOC);
  476.   PhonixReplace1(START , NewName, "YJ"   , "Y"    , NON, VOC);
  477.   PhonixReplace2(START , NewName, "GH"   , "G"    );
  478.   PhonixReplace1(END   , NewName, "E"    , "GH"   , VOC, NON);
  479.   PhonixReplace2(START , NewName, "CY"   , "S"    );
  480.   PhonixReplace2(ALL   , NewName, "NX"   , "NKS"  );
  481.   PhonixReplace2(START , NewName, "PF"   , "F"    );
  482.   PhonixReplace2(END   , NewName, "DT"   , "T"    );
  483.   PhonixReplace2(END   , NewName, "TL"   , "TIL"  );
  484.   PhonixReplace2(END   , NewName, "DL"   , "DIL"  );
  485.   PhonixReplace2(ALL   , NewName, "YTH"  , "ITH"  );
  486.   PhonixReplace1(START , NewName, "TJ"   , "CH"   , NON, VOC);
  487.   PhonixReplace1(START , NewName, "TSJ"  , "CH"   , NON, VOC);
  488.   PhonixReplace1(START , NewName, "TS"   , "T"    , NON, VOC);
  489.   PhonixReplace1(ALL   , NewName, "TCH"  , "CH"   );
  490.   PhonixReplace1(MIDDLE, NewName, "WSK"  , "VSKIE", VOC, NON);
  491.   PhonixReplace1(END   , NewName, "WSK"  , "VSKIE", VOC, NON);
  492.   PhonixReplace1(START , NewName, "MN"   , "N"    , NON, VOC);
  493.   PhonixReplace1(START , NewName, "PN"   , "N"    , NON, VOC);
  494.   PhonixReplace1(MIDDLE, NewName, "STL"  , "SL"   , VOC, NON);
  495.   PhonixReplace1(END   , NewName, "STL"  , "SL"   , VOC, NON);
  496.   PhonixReplace2(END   , NewName, "TNT"  , "ENT"  );
  497.   PhonixReplace2(END   , NewName, "EAUX" , "OH"   );
  498.   PhonixReplace2(ALL   , NewName, "EXCI" , "ECS"  );
  499.   PhonixReplace2(ALL   , NewName, "X"    , "ECS"  );
  500.   PhonixReplace2(END   , NewName, "NED"  , "ND"   );
  501.   PhonixReplace2(ALL   , NewName, "JR"   , "DR"   );
  502.   PhonixReplace2(END   , NewName, "EE"   , "EA"   );
  503.   PhonixReplace2(ALL   , NewName, "ZS"   , "S"    );
  504.   PhonixReplace1(MIDDLE, NewName, "R"    , "AH"   , VOC, CON);
  505.   PhonixReplace1(END   , NewName, "R"    , "AH"   , VOC, NON); /* VOC,CON */
  506.   PhonixReplace1(MIDDLE, NewName, "HR"   , "AH"   , VOC, CON);
  507.   PhonixReplace1(END   , NewName, "HR"   , "AH"   , VOC, NON); /* VOC,CON */
  508.   PhonixReplace1(END   , NewName, "HR"   , "AH"   , VOC, NON);
  509.   PhonixReplace2(END   , NewName, "RE"   , "AR"   );
  510.   PhonixReplace1(END   , NewName, "R"    , "AH"   , VOC, NON);
  511.   PhonixReplace2(ALL   , NewName, "LLE"  , "LE"   );
  512.   PhonixReplace1(END   , NewName, "LE"   , "ILE"  , CON, NON);
  513.   PhonixReplace1(END   , NewName, "LES"  , "ILES" , CON, NON);
  514.   PhonixReplace2(END   , NewName, "E"    , ""     );
  515.   PhonixReplace2(END   , NewName, "ES"   , "S"    );
  516.   PhonixReplace1(END   , NewName, "SS"  , "AS"    , VOC, NON);
  517.   PhonixReplace1(END   , NewName, "MB"  , "M"     , VOC, NON);
  518.   PhonixReplace2(ALL   , NewName, "MPTS" , "MPS"  );
  519.   PhonixReplace2(ALL   , NewName, "MPS"  , "MS"   );
  520.   PhonixReplace2(ALL   , NewName, "MPT"  , "MT"   );
  521.  
  522.   /* calculate Key for NewName */
  523.   PhonixCode(NewName, Key);
  524.  
  525. #ifdef DEBUG
  526.   printf("NewName = %s\n", NewName);  
  527.   printf("Code    = %s\n\n", Key);  
  528. #endif /* DEBUG */
  529. }
  530.  
  531.  
  532. /****************************************************************************
  533. NAME    : Soundex
  534. INPUT   : char *Name --- string to calculate soundex code for
  535. OUTPUT  : char *Key  --- soundex code of Name
  536. FUNCTION: Soundex calculates the soundex code for the string Name.
  537. ****************************************************************************/
  538.  
  539. void Soundex (Name, Key)
  540. char *Name;
  541. char *Key;
  542. {
  543.   /* use new variable NewName to remain Name unchanged */
  544.   char NewName[50];
  545.   int  i; 
  546.  
  547.   strcpy(NewName, Name);
  548.  
  549.   /* uppercase NewName */
  550.   for (i=0; i < strlen(NewName); i++)
  551.     if (islower(NewName[i])) 
  552.       NewName[i] = toupper(NewName[i]);
  553.  
  554.   /* calculate Key for Name */
  555.   SoundexCode(NewName, Key);
  556.   /* fprintf(stderr, "Soundex: %s -> %s\n", Name, Key); */
  557. }
  558.  
  559.  
  560. /****************************************************************************
  561. Now the two procedures PrintCode() and main() follow which will only be
  562. included if TEST is defined.
  563. ****************************************************************************/
  564.  
  565. #ifdef TEST
  566.  
  567. void PrintCode (Name)
  568. unsigned char *Name;
  569. {
  570.   unsigned char SoundexName[SoundexLen+1];
  571.   unsigned char PhonixName[PhonixLen+1];
  572.  
  573.   Soundex(Name, SoundexName);
  574.   Phonix(Name, PhonixName);
  575.   printf("%20s --> %s %s\n", Name, SoundexName, PhonixName);
  576. }
  577.  
  578.  
  579. void main ()
  580. {
  581.   unsigned char s[256];
  582.   PrintCode("CLASSEN");
  583.   PrintCode("WRITE");
  584.   PrintCode("WRIGHT");
  585.   PrintCode("RITE");
  586.   PrintCode("WHITE");
  587.   PrintCode("WAIT");
  588.   PrintCode("WEIGHT");
  589.   PrintCode("KNIGHT");
  590.   PrintCode("NIGHT");
  591.   PrintCode("NITE");
  592.   PrintCode("GNOME");
  593.   PrintCode("NOAM");
  594.   PrintCode("SMIDT");
  595.   PrintCode("SMITH");
  596.   PrintCode("SCHMIT");
  597.   PrintCode("CRAFT");
  598.   PrintCode("KRAFT");
  599.   PrintCode("REES");
  600.   PrintCode("REECE");
  601.   PrintCode("YAEGER");
  602.   PrintCode("YOGA");
  603.   PrintCode("EAGER");
  604.   PrintCode("AUGER");
  605.   PrintCode("Krueger");
  606.   PrintCode("Kruger");
  607.   PrintCode("Krⁿger");
  608.   while (1) {
  609.     PrintCode(gets(s));
  610.   }
  611. }
  612.  
  613. #endif /* TEST*/
  614.